﻿namespace ScrumLite.WebUx.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Web.Mvc;
    using GoogleChartSharp;
    using ScrumLite.Services;
    using ScrumLite.Services.Contracts;
    using ScrumLite.WebUx.Models;
    using ScrumLite.Gateways;
    using System.Globalization;
    using System.Configuration;

    public class BurndownsController : ContextBaseController
    {       
        IRequestsService requestsService;       

        public BurndownsController() : this(new RequestsServiceClient())
        {
        }

        public BurndownsController(IRequestsService requestsService)
        {
            this.requestsService = requestsService;
        }
        
        public void BurndownsMetrics(string projectId)
        {
            //product Burndown
            int totalWeight = requestsService.GetRequestsTotalWeight(projectId);
            Dictionary<int, int> weeklyWeights = requestsService.GetWeeklyWeight(projectId);

            int committedTotalWeight = requestsService.GetCommittedRequestsTotalWeight(projectId);
            Dictionary<DayOfWeek, int> dailyWeights = requestsService.GetCommittedDailyWeight(projectId);

            BurndownsMetricsData data = new BurndownsMetricsData(weeklyWeights, totalWeight, dailyWeights, committedTotalWeight);

            data.GChartProductBurndownChart = CreateBurndownChartUrl(data);
            data.GChartSprintBurndownChart = CreateSprintBurndownChartUrl(data);
                        
            RenderView("BurndownsMetrics", data);
        }       

        #region Google Charts helper methods

        //TODO: Refactor both methods in one generic
        private static string CreateSprintBurndownChartUrl(BurndownsMetricsData data)
        {        
            //chart metadata
            LineChart chartBuilder = new LineChart(500, 250, LineChartType.SingleDataSet);
            chartBuilder.AddLineStyle(new LineStyle(3, 1, 0));
            chartBuilder.AddLineStyle(new LineStyle(3, 1, 0));
            chartBuilder.AddLineStyle(new LineStyle(1, 6, 3));            
            chartBuilder.SetTitle("Sprint Burndown Chart");
            chartBuilder.SetLegend(new string[] { "Trend", "Weight remaining", "Weight Average" });
            chartBuilder.SetDataSetColors(new string[] { "FF0000", "55FF55", "0000FF"  });
            
            List<float> chartData = new List<float>();
            List<float> trendData = new List<float>();
            List<string> dayLabels = new List<string>();
            int tempWeight = data.CommittedTotalWeight;
            int lastDay = (int)DayOfWeek.Sunday;
            chartData.Add(tempWeight);
            trendData.Add(tempWeight);
            dayLabels.Add(".");
            foreach (KeyValuePair<DayOfWeek, int> day in data.DailyWeight)
            {
                tempWeight -= day.Value;
                chartData.Add(tempWeight);
                lastDay = (int)day.Key;
                dayLabels.Add(string.Format(CultureInfo.InvariantCulture, "D{0}", lastDay));
                trendData.Add(tempWeight);
            }

            double? average = 0;
            if (data.DailyWeight.Count > 0)
            {
                average = data.DailyWeight.Average(w => w.Value);
            }
                        
            if (average.HasValue)
            {
                while (tempWeight > 0 && lastDay < 6)
                {
                    tempWeight -= Convert.ToInt32(average.Value);
                    if (tempWeight < 0)
                    {
                        tempWeight = 0;
                    }
                    trendData.Add(tempWeight);
                    lastDay++;
                    dayLabels.Add(string.Format(CultureInfo.InvariantCulture, "D{0}", lastDay));
                    chartData.Add(chartData.Last());
                }
            }

            ChartAxis weeklyAxis;
            if (dayLabels.Count > 0)
            {                
                weeklyAxis = new ChartAxis(ChartAxisType.Bottom, dayLabels.ToArray());
            }
            else
            {
                weeklyAxis = new ChartAxis(ChartAxisType.Bottom, new string[] { "." });
            }
            chartBuilder.AddAxis(weeklyAxis);

            int maxValueLabel = (Convert.ToInt32(data.CommittedTotalWeight / 10) + 1) * 10;
            ChartAxis unitAxis = new ChartAxis(ChartAxisType.Left);
            unitAxis.SetRange(0, maxValueLabel);
            chartBuilder.AddAxis(unitAxis);

            
            List<float[]> allData = new List<float[]>();
            allData.Add(trendData.ToArray());
            allData.Add(chartData.ToArray());
            allData.Add(new float[] { (float)average, (float)average });            
            chartBuilder.SetData(allData, maxValueLabel);

            return chartBuilder.GetUrl();           
        }

        private static string CreateBurndownChartUrl(BurndownsMetricsData data)
        {
            //chart metadata
            LineChart chartBuilder = new LineChart(500, 250, LineChartType.SingleDataSet);
            chartBuilder.AddLineStyle(new LineStyle(3, 1, 0));
            chartBuilder.AddLineStyle(new LineStyle(3, 1, 0));
            chartBuilder.AddLineStyle(new LineStyle(1, 6, 3));
            chartBuilder.SetTitle("Product Burndown Chart");
            chartBuilder.SetLegend(new string[] { "Trend", "Weight remaining", "Weight Average" });
            chartBuilder.SetDataSetColors(new string[] { "FF0000", "55FF55", "0000FF" });

            List<float> chartData = new List<float>();
            List<float> trendData = new List<float>();
            List<string> weekLabels = new List<string>();
            int tempWeight = data.TotalWeight;
            int lastWeek = 0;
            chartData.Add(tempWeight);
            trendData.Add(tempWeight);
            weekLabels.Add(".");
            foreach (KeyValuePair<int, int> week in data.WeeklyWeight)
            {
                tempWeight -= week.Value;
                chartData.Add(tempWeight);
                lastWeek = week.Key;
                weekLabels.Add(string.Format(CultureInfo.InvariantCulture, "W{0}", lastWeek));
                trendData.Add(tempWeight);
            }

            double? average = 0;
            if (data.WeeklyWeight.Count > 0)
            {
                average = data.WeeklyWeight.Average(w => w.Value);
            }

            if (average.HasValue)
            {
                while (tempWeight > 0)
                {
                    tempWeight -= Convert.ToInt32(average.Value);
                    if (tempWeight < 0)
                    {
                        tempWeight = 0;
                    }
                    trendData.Add(tempWeight);
                    lastWeek++;
                    weekLabels.Add(string.Format(CultureInfo.InvariantCulture, "W{0}", lastWeek));
                    chartData.Add(chartData.Last());
                }
            }

            ChartAxis weeklyAxis;
            if (weekLabels.Count > 0)
            {
                weeklyAxis = new ChartAxis(ChartAxisType.Bottom, weekLabels.ToArray());
            }
            else
            {
                weeklyAxis = new ChartAxis(ChartAxisType.Bottom, new string[] { "." });
            }
            chartBuilder.AddAxis(weeklyAxis);

            int maxValueLabel = (Convert.ToInt32(data.TotalWeight / 10) + 1) * 10;
            ChartAxis unitAxis = new ChartAxis(ChartAxisType.Left);
            unitAxis.SetRange(0, maxValueLabel);
            chartBuilder.AddAxis(unitAxis);


            List<float[]> allData = new List<float[]>();
            allData.Add(trendData.ToArray());
            allData.Add(chartData.ToArray());
            allData.Add(new float[] { (float)average, (float)average });
            chartBuilder.SetData(allData, maxValueLabel);

            return chartBuilder.GetUrl();
        }
       
        #endregion              
    }
}
